package com.briansteen.painterface;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.Random;

import cc.creativecomputing.graphics.CCGraphics;

public class BasicColor {
	public float colorX = 0;
	public float colorY = 0;
	public float trailX = 0;
	public float trailY = 0;
	public float oldX = 0;
	public float oldY = 0;
	public float z;
	public float trailOldX = 0;
	public float trailOldY = 0;
	public float[] alphas;
	public float[] transitionX;
	public float[] transitionXO;
	public float[] transitionY;
	public float[] transitionYO;
	private float oldSpeed = 0;
	private float oldRadius = 0;
	public float radius = 0;
	public int linesAmount = 200;
	public float particleThreshold = .028f;
	public float radiusThreshold = .4f;
	public float brushSize = 1;
	public float brushSizeX = 1;
	public float brushSizeY = 1;
	public float linesWeight = 1;
	public float dryness = .5f;
	public float gravity = .2f;
	public float drag = .68f;
	public boolean isWet = false;
	public boolean randomness = false;
	public float randomradius;
	public boolean positionTransition = true;
	public float brushPI = 15;
	public float ID = 1;
	private long timeStamp;
	public boolean isDrop = false;
	public boolean isTypo = false;
	public boolean isPDF = false;
	public float followSpeed = .25f;
	public float randomSize = 1;
	public boolean isSplatter = false;
	public float red = .8f;
	public float blue = 0;
	public float green = 0;
	private int Count = 0;
	
	private Random r;
	
	public String myGene;
	
	public ColorParticle[] colorParticles = new ColorParticle[0];

	public BasicColor(float startX, float startY) {
		this(startX, startY, (long)0);
	}
	
	public BasicColor(float startX, float startY, long randomSeed) {
		
		trailX = trailOldX = startX;
		trailY = trailOldY = startY;
		
		colorX = startX;
		colorY = startY;
		
		oldX = startX;
		oldY = startY;
		
		r = new Random(randomSeed);
		
		int step = (int)(r.nextFloat()*50);
		String[] clownosomes = {"cos", "sin", "asin", "acos", "atan", "plus", "minus", "morestroke", "lesstroke", "circle"};
		for(int i=0;i<step;i++) {
			if(r.nextFloat() < .5f)
				myGene += clownosomes[(int)(r.nextFloat()*clownosomes.length)] + "|";
			else myGene += randRange(-100,100) + "|";
		}		
		// fill alphas array
		transitionX = new float[linesAmount];
		transitionXO = new float[linesAmount];
		transitionY = new float[linesAmount];
		transitionYO = new float[linesAmount];
		alphas = new float[linesAmount];
		for (int i = 0; i < linesAmount; i++) {
			alphas[i] = .2f + (float) r.nextFloat() * .1f;
			transitionX[i] = startX;
			transitionXO[i] = startX;
			transitionY[i] = startY;
			transitionYO[i] = startY;
		}
		timeStamp = System.currentTimeMillis();
	}

	/**
	 * draws color
	 * 
	 * @param stageSprite
	 */
	public void draw(CCGraphics g2d, float destX, float destY) {
		Count++;
		// position
		trailX += (destX - trailX) * 1f;// followSpeed;
		trailY += (destY - trailY) * 1f;// followSpeed;
		// speed
		float speedX = trailX - trailOldX;
		float speedY = trailY - trailOldY;
		float speed = (float) Math.sqrt(speedX * speedX + speedY * speedY);

		radius = createRadius(speed);
		long millis = System.currentTimeMillis();
		if (randomness && speed < 10) {
			float deg = (float) Math.sin(millis * .004f)
					* ((float) Math.PI * 2)
					+ (float) Math.cos((float) Math.sin(millis * .003f) * 2)
					* 5 - (float) Math.sin(millis * .006f) * 5;
			randomradius = (float) Math.sin(millis * .002f) * (4 * randomSize)
					+ (float) Math.cos(deg * .01f) * (3 * randomSize);
			if (isDrop)
				randomradius *= .01;
			trailX += Math.cos(deg) * randomradius;
			trailY += Math.sin(deg) * randomradius;
		}
		
		if(speed < 500) {
		
			// draw lots of lines
			for (int i = 0; i < linesAmount; i++) {
	
				radius = Math.max(0, radius);
				// if(randomness) radius += r.nextFloat()*.5
				float ratio1 = ((float)i / (linesAmount - 1))
						* ((float) Math.PI * brushPI);
				float ratio2 = ((float)i / (linesAmount - 1)) * (brushSize * radius);
				float ratio2Old = ((float)i / (linesAmount - 1)) * (brushSize * oldRadius);
				// positions
				float lineXO = trailOldX + (float) Math.cos(ratio1) * ratio2Old
						* brushSizeX;
				float lineX = trailX + (float) Math.cos(ratio1) * ratio2
						* brushSizeX;
				float lineYO = trailOldY + (float) Math.sin(ratio1) * ratio2Old
						* brushSizeY;
				float lineY = trailY + (float) Math.sin(ratio1) * ratio2
						* brushSizeY;
	
				/**
				 * add fuzzyness
				 */
	
				// alphas
				// dryness -= .00005;
				if (dryness < 0)
					dryness = 0;
				// setAlpha(i, radius);
	
				// position transition
				// float currTransitionX = transitionX[i];
				// float currTransitionY = transitionY[i];
				if (positionTransition) {
					float newX = transitionX[i] + randRange(-.1f, .1f);
					newX = Math.max(-5, newX);
					newX = Math.min(5, newX);
					float newX1 = newX + (newX - transitionX[i]) * .3f;
					transitionX[i] += (newX1 - transitionX[i]) * .7f;
	
					float newY = transitionY[i] + randRange(-.1f, .1f);
					newY = Math.max(-5, newY);
					newY = Math.min(5, newY);
					float newY1 = newY + (newY - transitionY[i]) * .3f;
					transitionY[i] += (newY1 - transitionY[i]) * .7f;
				} else {
					transitionX[i] = 0;
					transitionY[i] = 0;
					transitionXO[i] = 0;
					transitionYO[i] = 0;
				}
	
				// draw
				if(Count > 2) {
					drawBrush(i, g2d, radius, lineXO + transitionXO[i], lineX
							+ transitionX[i], lineYO + transitionYO[i], lineY
							+ transitionY[i], alphas[i]);
					
					// add particles
					if (r.nextFloat() < particleThreshold && radius > radiusThreshold) {
						colorParticles = addArrayElement(new ColorParticle(lineXO
								+ transitionXO[i], lineYO + transitionYO[i], lineX
								+ transitionX[i], lineY + transitionY[i], new Color(0),
								alphas[i]*.25f, gravity, drag, linesWeight * radius, isWet));
						colorParticles[colorParticles.length-1].red = red;
						colorParticles[colorParticles.length-1].green = green;
						colorParticles[colorParticles.length-1].blue = blue;
					}
				}				
				// stick particles together
				/*
				int particleLen = colorParticles.length;
				for(int k=0;k<particleLen;k++) {
					ColorParticle particleK = colorParticles[k];
					for(int l=k+1;l<particleLen;l++) {
						ColorParticle particleL = colorParticles[l];
						float pdx = particleK.currX - particleL.currX;
						float pdy = particleK.currY - particleL.currY;
						float d = (float)Math.sqrt(pdx*pdx + pdy*pdy);
						if(d<5) {
							particleK.currX -= (particleL.currX - particleK.currX)*.125f;
							particleK.currY -= (particleL.currY - particleK.currY)*.125f;
						}
						else if(d<10) {
							particleK.currX += (particleL.currX - particleK.currX)*.125f;
							particleK.currY += (particleL.currY - particleK.currY)*.125f;
						}
					}
				}
				*/
				transitionXO[i] = transitionX[i];
				transitionYO[i] = transitionY[i];
	
			}
		}
		trailOldX = trailX;
		trailOldY = trailY;
		
		oldSpeed = speed;
		oldRadius = radius;
	}

	/**
	 * draws particles
	 * 
	 * @param stageSprite
	 */
	public void drawParticles(CCGraphics g2d) {
		// draw particles
		for (int i = 0; i < colorParticles.length; i++) {
			if (!colorParticles[i].isFinished) {
				// draw
				colorParticles[i].draw(g2d);
			} else {
				colorParticles = removeArrayElement(i);
			}
		}
	}

	/**
	 * resets for a fresh new stroke
	 */
	public void reset() {
		// colorParticles = new Array();
		oldSpeed = 0;
		oldRadius = 0;
		for (int i = 0; i < linesAmount; i++) {
			alphas[i] = .2f + (float) r.nextFloat() * .1f;
			transitionX[i] = 0;
			transitionXO[i] = 0;
			transitionY[i] = 0;
			transitionYO[i] = 0;
		}
		timeStamp = System.currentTimeMillis();
	}

	/**
	 * fuzzy alpha for brush
	 * 
	 * @param ID
	 * @param radius
	 */
	private void setAlpha(int ID, float radius) {
		float newAlpha = alphas[ID] + randRange(-.1f, .1f);
		newAlpha = Math.max(0, newAlpha);
		newAlpha = Math.min(dryness * radius, newAlpha);
		float newAlpha1 = alphas[ID] + (newAlpha - alphas[ID]) * .3f;
		alphas[ID] += (newAlpha1 - alphas[ID]) * .7f;
	}

	/**
	 * thickness of brush
	 * 
	 * @param speed
	 * @return
	 */
	public float createRadius(float speed) {
		return 1 - speed / 30;
	}

	/**
	 * draws into sprite
	 */
	public void drawBrush(int ID, CCGraphics g2d, float radius, float lineXO,
			float lineX, float lineYO, float lineY, float alpha) {
//		System.out.println("drawbrush");
		Color theColor = new Color(red, green, blue,alpha);
		g2d.color(red, green, blue,alpha);
		g2d.strokeWeight(linesWeight * radius);
		g2d.line((int) lineXO, (int) lineYO, (int) lineX, (int) lineY);
		
		// System.out.println((int)lineXO + " " + (int)lineX + " " + (int)lineYO + " " + (int)lineY);
		
	}

	/**
	 * random number between min and max
	 * 
	 * @param min
	 * @param max
	 * @return
	 */
	public float randRange(float min, float max) {
		float randomNum = (float) Math.floor((float) r.nextFloat()
				* (max - min + 1))
				+ min;
		return randomNum;
	}

	/**
	 * alters values to become a drop
	 */
	public void isDrop(boolean isADrop) {
		isDrop = isADrop;
		if (isDrop) {
			particleThreshold = .04f;
			radiusThreshold = .4f;
			brushSize = .2f;
			dryness = .2f;
			linesAmount = 100;
		}
	}

	/**
	 * Creates a new array from colorParticles adding an element with value n.
	 */
	public ColorParticle[] addArrayElement(ColorParticle cp) {
		int len = colorParticles.length;
		ColorParticle[] newarray = new ColorParticle[len + 1];
		for (int i = 0; i < len; i++) {
			newarray[i] = colorParticles[i];
		}
		newarray[len] = cp;
		return newarray;
	}

	/**
	 * Creates a new array from intarray skipping element n.
	 */
	public ColorParticle[] removeArrayElement(int n) {
		int len = colorParticles.length;
		ColorParticle[] newarray = new ColorParticle[len - 1];
		for (int i = 0; i < len; i++) {
			if (i < n)
				newarray[i] = colorParticles[i];
			if (i > n)
				newarray[i - 1] = colorParticles[i];
		}
		return newarray;
	}
}
